﻿using System.Collections.Generic;
using System.Linq;
using Cms.Application.Admin.Views;
using Cms.Application.IO;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;

namespace Cms.Application.Admin.Presenters
{
    public class EditSitePresenter : BasePresenter
    {
        private readonly IEditSiteView _view;
        public IDiskAccess DiskAccess;
        private readonly Administrator _administrator;

        public EditSitePresenter(IEditSiteView view)
            : this(view, new RepositoryFactory())
        {
            DiskAccess = new DiskAccess();
        }
        
        public EditSitePresenter(IEditSiteView view, IRepositoryFactory repositoryFactory)
            : base(view, repositoryFactory)
        {
            _view = view;
            _administrator = AdministratorRepository.GetAdministrator(_view.AdministratorID);
            if (!_administrator.HasPermission.EditSite)
                _view.RedirectToPermissionDeniedPage();
        }

        public void Initialize()
        {
            _view.SetAdministrators(AdministratorRepository.GetAdministrators());
            if (_view.SiteID < 0)
            {
                _view.Online = true;
            }
            else
            {
                Site site = SiteRepository.GetSite(_view.SiteID);
                if (site == null)
                {
                    _view.RedirectToBadRequestParameterPage();
                    return;
                }
                _view.Domain = site.Domain;
                _view.Online = site.Online;
                _view.RootMediaFolder = site.RootMediaFolder;
                _view.SetLocales(site.Locales);
                _view.SelectedLocaleID = site.DefaultLocale.ID;
                _view.SetMasterTemplates(site.MasterTemplates);
                if (site.MasterTemplates.Count > 0)
                    _view.SelectedMasterTemplateID = site.DefaultMasterTemplate.ID;
                _view.SetDetailTemplates(site.DetailTemplates);
                if (site.DetailTemplates.Count > 0)
                    _view.SelectedDetailTemplateID = site.DefaultDetailTemplate.ID;
            }
        }

        public bool IsAvailableTo(Administrator admin)
        {
            Site site = SiteRepository.GetSite(_view.SiteID);
            return admin.AvailableSites.FirstOrDefault(s => site != null && s.ID == site.ID) != null || admin.Group.ID == 1;
        }

        private void Validate()
        {
            if (_view.Domain == "")
            {
                AddValidationError(GetText(_view, "NoDomainError"));
            }
            else
            {
                bool domainExists = false;
                foreach (Site existingSite in SiteRepository.GetSites())
                {
                    if (_view.Domain.ToLower() == existingSite.Domain.ToLower() && _view.SiteID != existingSite.ID)
                    {
                        domainExists = true;
                        break;
                    }
                    if (existingSite.AliasDomains.Any(alias => _view.Domain.ToLower() == alias.ToLower()))
                    {
                        domainExists = true;
                    }
                    if (existingSite.Locales.Any(existingLocale => existingLocale.AliasDomain != null && _view.Domain.ToLower() == existingLocale.AliasDomain.ToLower()))
                    {
                        domainExists = true;
                    }
                    if (domainExists)
                        break;
                }
                if (domainExists)
                {
                    AddValidationError(GetText(_view, "DomainAlreadyInUseError"));
                }
            }
            if (_view.SiteID < 0)
            {
                if (_view.DefaultLocaleName == "")
                {
                    AddValidationError(GetText(_view, "NoDefaultLocaleNameError"));
                }
                if (_view.DefaultLocaleRegion == "")
                {
                    AddValidationError(GetText(_view, "NoDefaultLocaleRegionError"));
                }
                if (_view.DefaultLocaleLanguage == "")
                {
                    AddValidationError(GetText(_view, "NoDefaultLocaleLanguageError"));
                }
                if (_view.DefaultLocaleCode == "")
                {
                    AddValidationError(GetText(_view, "NoDefaultLocaleCodeError"));
                }
            }
            if (_view.RootMediaFolder == "")
            {
                AddValidationError(GetText(_view, "NoRootMediaFolderError"));
            }
            else
            {
                
                switch (_view.RootMediaFolder.ToLower())
                {
                    case "__system":
                    case "admin":
                    case "bin":
                    case "app_data":
                    case "app_code":
                    case "jwplayer":
                    case "obj":
                    case "properties":
                    case "swfupload":
                        AddValidationError(GetText(_view, "RootMediaFolderNameNotAllowedError"));
                        break;
                }
            }
        }
        
        public void Save()
        {
            Validate();
            if (!IsValid)
                return;
            Site site;
            if (_view.SiteID < 0)
            {
                site = new Site();
                var locale = new Locale();
                var localeTranslation = new LocaleTranslation();
                site.Locales.Add(locale);
                site.DefaultLocale = locale;
                locale.UrlCode = _view.DefaultLocaleCode;
                locale.Site = site;
                // All not-null properties must be set before saving
                site.Domain = _view.Domain;
                site.RootMediaFolder = _view.RootMediaFolder;
                site.Online = true;
                SiteRepository.SaveSite(site); // Save to get an ID for the locale
                localeTranslation.Name = _view.DefaultLocaleName;
                localeTranslation.Language = _view.DefaultLocaleLanguage;
                localeTranslation.Region = _view.DefaultLocaleRegion;
                locale.Translations.Add(locale.ID, localeTranslation);
                SiteRepository.SaveSite(site); // Save again to persist the locale translation
                DiskAccess.CreateDirectory(_view.RootMediaFolder);
            }
            else
            {
                site = SiteRepository.GetSite(_view.SiteID);
                DiskAccess.CreateDirectory(site.RootMediaFolder);
                DiskAccess.MoveDirectory(site.RootMediaFolder, _view.RootMediaFolder);
                site.Domain = _view.Domain;
                site.RootMediaFolder = _view.RootMediaFolder;
                site.Online = true;
            }
            IList<Administrator> adminsBefore = new List<Administrator>();
            foreach (Administrator admin in site.Administrators)
            {
                admin.AvailableSites.Remove(site);
                adminsBefore.Add(admin);
            }
            site.Administrators.Clear();
            foreach (Administrator admin in
                _view.GetSelectedAdministratorIDs().Select(id => AdministratorRepository.GetAdministrator(id)))
            {
                site.Administrators.Add(admin);
                admin.AvailableSites.Add(site);
            }

            foreach (Administrator admin in adminsBefore)
            {
                bool found = false;
                foreach (int id in _view.GetSelectedAdministratorIDs())
                    if (admin.ID == id)
                        found = true;
                if (found)
                    continue;
                admin.ForceLogout = true;
                AdministratorRepository.SaveAdministrator(admin);
            }
            AdministratorGroup adminGroup = AdministratorRepository.GetGroup(1);
            foreach (Administrator admin in adminGroup.Administrators)
            {
                if (admin.AvailableSites.FirstOrDefault(s => s.ID == site.ID) == null)
                {
                    admin.AvailableSites.Add(site);
                    site.Administrators.Add(admin);
                }
            }
            SiteRepository.SaveSite(site);
        }
    }
}